/*-------------------------------------------------------------------------
 - Copyright (c) 2024-2025 [XD-AMCC TEAM]
 - [XD-AMCC] is licensed under Mulan PSL v2.
 - You can use this software according to the terms and conditions of the Mulan PSL v2.
 - You may obtain a copy of Mulan PSL v2 at:
 -          http://license.coscl.org.cn/MulanPSL2
 - THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES
 - OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 - TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 - See the Mulan PSL v2 for more details.
 ------------------------------------------------------------------------*/


/**
 * @file
 * @brief  Interface of class symbol table entry.
 *
 * @author  WXQ#XDU
 * @date    2024.12
 */

#pragma once


#ifndef AMCC_SYMENTRY_H
#define AMCC_SYMENTRY_H

#include "tree.h"
#include "typesys.h"

AMCC_DECL_BEGIN

/**
 * @brief Type of init-value-expression for an element of array.
 *
 * Each instance corresponds to an initializer(expression)
 * for a scalar element in the initializer-list of an array.
 */
typedef struct  scalar_init_expr {
    t_tree_ptr  exprNode; // parse tree node of this scalar initializer

    // indexes of this scalar initializer:
    // indexHolders[0] holds the dimension(N) of an array,
    // indexHolders[k], 1<=k<=N, holds the index of dimension k
    int      *  indexHolders;
} t_init_expr, * t_init_expr_ptr;

/**
 * @brief Type of variable information in a symbol table entry.
 * This type is also used for function parameters.
 *
 * @attention  All attributes SHOULD be accessed using API below
 *             named as "symentry_var_*()" or "symentry_arr_*()".
 */
typedef struct variable_symInfo {
    t_type_ptr typePtr;  //!< data type
    size_t     offset;   //!< offset of memory allocated for variable

    /// tree node of an initializer, null for no initializer
    t_tree_ptr initializerNode;

    /// All init-values-expression for scalar elements of an array.
    ///
    /// The underlying type is list &lt; t_init_expr_ptr &gt;.
    /// For a scalar variable, this field is NULL.
    t_list_ptr  initExprs;
} t_var_symInfo, * t_var_symInfo_ptr;

// Whether a variable is an array or not
#define VAR_IS_ARRAY(dimensions)  (ARRAY_DIMS(dimensions) > 0)

// Whether a variable is a scalar
#define VAR_IS_SCALAR(dimensions)  (ARRAY_DIMS(dimensions) <= 0)

// Get variable dimension, return 0 for a scalar var
#define ARRAY_DIMS(dimensions) ((NULL == (dimensions)) ? 0 : (dimensions)[0])


/**
 * @brief Type of function information in a symbol table entry.
 *
 * @attention  All attributes SHOULD be accessed using API below
 *             named as "symentry_func_*()".
 */
typedef struct function_symInfo {
    t_type_ptr     typePtr;    //!< function type

    /// "parametersList" keeps the order of parameters as input,
    ///     and supplies dimensions of array.
    ///
    /// These names, as symtable entries, are stored in a
    ///     symbol-table indicated by field 'symTable'.
    /// The real type is t_list &lt; t_symentry_ptr &gt;.
    //
    t_list     parameterList;

    /// Symbol table of this function.
    ///
    /// The table will store all parameters and names declared in
    /// the outermost block of this function.
    //
    struct symbol_table * symTablePtr;
} t_func_symInfo, * t_func_symInfo_ptr;


/**
 * @brief Type of label information in a symbol table entry.
 *
 * This information is helpful to code generation.
 *
 * @attention  All attributes SHOULD be accessed using API below
 *             named as "symentry_label_*()".
*/
typedef struct label_symInfo {

    /// Pointer to a node marked with non-terminal 'labeledStatement',
    /// this node is the parent of label-name definition.
    //
    t_tree_ptr  labeledStatementNode;

} t_label_symInfo, * t_label_symInfo_ptr;


/**
 * @brief Type of entry in a symbol table.
 *
 * All instances are bound to a tree node that is the definition of a name,
 * and it is marked with function-name, variable-name or label-name.
 *
 * @note All attributes SHOULD be accessed using API below
 *       named as "symentry_*()".
 */
typedef struct symtable_entry {

    /// Map's Key.
    /// The key of symbol entry is usually a string or rather a reference
    /// to a string, BUT
    /// we use alternatively references to tree node marked with an ID
    /// token (var-name, func-name, or label-name), and this node represents
    /// the definition of this name.
    //
    // That is:
    // this == node->grammarSymbol.instance.terminal->pSymEntry
    t_tree_ptr  definitionTreeNode;

    /// Map's value, the content of this symbol table entry
    union {
        /// Valid only if TREE_IS_FUNCNAME(definitionTreeNode) is true
        t_func_symInfo_ptr     funcInfo;

        /// Valid only if TREE_IS_VARNAME(definitionTreeNode) is true
        t_var_symInfo_ptr      varInfo;

        /// Valid only if TREE_IS_LABELNAME(definitionTreeNode) is true
        t_label_symInfo_ptr    labelInfo;
    } content;

} t_symentry, * t_symentry_ptr ;


// -----------------------------------------------------------------------
/// @name API of class symentry
/// @{

/**
 * @brief  Get the parse tree node corresponding to this entry.
 *
 * This parse tree node is marked with an ID token (a name),
 * and this node represents the definition of this name.
 *
 * @param pThis pointer to this symbol entry
 * @return Return the parse tree node corresponding to this entry.
 */
extern t_tree_ptr symentry_treenode(t_symentry_ptr pThis);

/**
 * @brief Whether this entry is of a function.
 * @param pThis  pointer to this symbol entry
 * @return Return true ONLY if this entry is of a function.
 */
extern bool symentry_is_func(t_symentry_ptr pThis);

/**
 * @brief Get the function information of given symbol entry.
 * @param pThis pointer to this symbol entry
 * @return Return the function info ONLY if this entry is of
 *         a function, otherwise return null.
 * @see symentry_is_func()
 */
extern t_func_symInfo_ptr symentry_func_info(t_symentry_ptr pThis);

/**
 * @brief Get the symbol table of given function symbol entry.
 * @param pThis pointer to this function symbol entry
 * @return Return a pointer to the symbol table ONLY if this
 *         entry is of a function, otherwise return null.
 * @see symentry_is_func()
 */
extern struct symbol_table* symentry_func_symtable(t_symentry_ptr pThis);

/**
 * @brief Get the function return type of given function symbol entry.
 * @param pThis pointer to this function symbol entry
 * @return Return the return type ONLY if this
 *         entry is of a function, otherwise return null.
 * @see symentry_is_func()
 */
extern t_type_ptr symentry_func_returntype(t_symentry_ptr pThis);

/**
 * @brief Get the parameters of given function symbol entry.
 * @param pThis pointer to this function symbol entry
 * @return Return a pointer to parameters ONLY if this
 *         entry is of a function, otherwise return null.
 * @see symentry_is_func()
 */
extern t_list_ptr symentry_func_params(t_symentry_ptr pThis);



/**
 * @brief Whether this entry is of a label.
 * @param pThis  pointer to this symbol entry
 * @return Return true ONLY if this entry is of a label.
 */
extern bool symentry_is_label(t_symentry_ptr pThis);

/**
 * @brief Get the label information of given symbol entry.
 * @param pThis pointer to this symbol entry
 * @return Return the function info ONLY if this entry is of
 *         a label, otherwise return null.
 * @see symentry_is_label()
 */
extern t_label_symInfo_ptr symentry_label_info(t_symentry_ptr pThis);

/**
 * @brief Get the parent of a parse tree node marked by a label name.
 *
 * This parent node is marked by non-terminal 'labeledStatement'.
 *
 * @param pThis pointer to this symbol entry
 * @return Return the function info ONLY if this entry is of
 *         a label, otherwise return null.
 * @see symentry_is_label()
 */
extern t_tree_ptr symentry_label_parent(t_symentry_ptr pThis);



/**
 * @brief Get the variable information of given symbol entry.
 * @param pThis pointer to this symbol entry
 * @return Return the function info ONLY if this entry is of
 *         a scalar variable or an array, otherwise return null.
 */
extern t_var_symInfo_ptr symentry_var_info(t_symentry_ptr pThis);

/**
 * @brief Whether this entry is of a scalar variable or not.
 * @param pThis  pointer to this symbol entry
 * @return Return true ONLY if this entry is of a scalar.
 */
extern bool symentry_is_scalar(t_symentry_ptr pThis);

/**
 * @brief Whether this entry is of an array or not.
 * @param pThis  pointer to this symbol entry
 * @return Return true ONLY if this entry is of an array.
 */

extern bool symentry_is_array(t_symentry_ptr pThis);

/**
 * @brief Get the dimension of a variable or an array.
 * @param pThis  pointer to this symbol entry
 * @return Return the dimension if this entry is of an array,
 *         otherwise return 0.
 */
extern int  symentry_var_dimcount(t_symentry_ptr pThis);
/**
 * @brief Get the number of array elements in the Kth dimension.
 * @param pThis  pointer to this symbol entry
 * @param k      which dimension, starting from 1
 * @return Return the number of elements if this entry is of an array,
 *         otherwise return 0.
 * @note  If k is out of range, this function returns 0.
 */
extern int  symentry_var_arraylimit(t_symentry_ptr pThis, int k);
/**
 * @brief Get the memory offset of a variable or array.
 * @param pThis  pointer to this symbol entry
 * @return Return the memory offset of a variable or array.
 * @return Return 0 if this entry is not of a variable or array.
 */
extern size_t symentry_var_offset(t_symentry_ptr pThis);
/**
 * @brief Get the memory size of a variable or array.
 * @param pThis  pointer to this symbol entry
 * @return Return the memory size of a variable or array.
 * @return Return 0 if this entry is not of a variable or array.
 */
extern size_t symentry_var_size(t_symentry_ptr pThis);
/**
 * @brief Get the tree node of an initializer for a variable or array.
 * @param pThis  pointer to this symbol entry
 * @return Return the tree node of an initializer for a variable or array.
 * @return Return NULL if this entry is not of a variable or array.
 */
extern t_tree_ptr symentry_var_initializer(t_symentry_ptr pThis);
/**
 * @brief Get the init-values-expressions of array elements.
 * @param pThis  pointer to this symbol entry
 * @return Return the init-values-expressions.
 * @return Return NULL if this entry is not of an array.
 */
extern t_list_ptr symentry_array_initExprs(t_symentry_ptr pThis);

/**
 * @brief Get the type object of this symbol entry.
 * @param pThis  pointer to the symbol entry
 * @return Return the type object of this symbol entry.
 *     Return NULL if this is not a variable or a function.
 */
extern t_type_ptr symentry_type(t_symentry_ptr pThis);

/**
 * @brief Generates a C-string representing the internal name
 *        for AMC data type.
 *
 * @param pThis    pointer to the symbol entry
 * @return C-string representing the internal name for AMC data type.
 */
extern const char * symentry_typename(t_symentry_ptr pThis);

/// @}
// -----------------------------------------------------------------------


AMCC_DECL_END

#endif //AMCC_SYMENTRY_H
